{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "15421774",
   "metadata": {},
   "source": [
    "# Google AI chat models (gemini-pro)\n",
    "\n",
    "Google AI의 `gemini`와 `gemini-vision` 모델뿐만 아니라 다른 생성 모델에 접근하려면 [langchain-google-genai](https://pypi.org/project/langchain-google-genai/) 통합 패키지의 `ChatGoogleGenerativeAI` 클래스를 사용하면 됩니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f5aa0991",
   "metadata": {},
   "outputs": [],
   "source": [
    "# !pip install -qU langchain-google-genai"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d0eaf060",
   "metadata": {},
   "source": [
    "### API KEY 발급받기\n",
    "\n",
    "- [링크](https://makersuite.google.com/app/apikey?hl=ko) 에서 API KEY를 발급받아주세요.\n",
    "- 사용자의 Google API 키를 환경 변수 `GOOGLE_API_KEY`로 설정합니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2c66ce72",
   "metadata": {},
   "outputs": [],
   "source": [
    "from dotenv import load_dotenv\n",
    "\n",
    "load_dotenv()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "39e009a2",
   "metadata": {},
   "outputs": [],
   "source": [
    "# LangSmith 추적을 설정합니다. https://smith.langchain.com\n",
    "# !pip install langchain-teddynote\n",
    "from langchain_teddynote import logging\n",
    "from langchain_teddynote.messages import stream_response\n",
    "\n",
    "# 프로젝트 이름을 입력합니다.\n",
    "logging.langsmith(\"CH04-Models\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3b62c0d4",
   "metadata": {},
   "source": [
    "langchain_google_genai 패키지에서 ChatGoogleGenerativeAI 클래스를 가져옵니다.\n",
    "\n",
    "- ChatGoogleGenerativeAI 클래스는 Google의 Generative AI 모델을 사용하여 대화형 AI 시스템을 구현하는 데 사용됩니다.\n",
    "- 이 클래스를 통해 사용자는 Google의 대화형 AI 모델과 상호 작용할 수 있습니다.\n",
    "- 모델과의 대화는 채팅 형식으로 이루어지며, 사용자의 입력에 따라 모델이 적절한 응답을 생성합니다.\n",
    "- ChatGoogleGenerativeAI 클래스는 LangChain 프레임워크와 통합되어 있어, 다른 LangChain 컴포넌트와 함께 사용할 수 있습니다.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8b5fb705",
   "metadata": {},
   "source": [
    "지원되는 모델 정보: https://ai.google.dev/gemini-api/docs/models/gemini?hl=ko"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "588610e5",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_google_genai import ChatGoogleGenerativeAI\n",
    "\n",
    "# ChatGoogleGenerativeAI 언어 모델을 초기화합니다.\n",
    "llm = ChatGoogleGenerativeAI(model=\"gemini-1.5-pro-latest\")\n",
    "\n",
    "# 프롬프트를 전달하여 결과를 생성합니다.\n",
    "answer = llm.stream(\"자연어처리에 대해서 간략히 설명해 줘\")\n",
    "\n",
    "# 결과를 출력합니다.\n",
    "stream_response(answer)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d4b53238",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.prompts import PromptTemplate\n",
    "\n",
    "# ChatGoogleGenerativeAI 언어 모델을 초기화합니다.\n",
    "model = ChatGoogleGenerativeAI(\n",
    "    model=\"gemini-1.5-flash-latest\",  # 사용할 모델을 지정합니다.\n",
    ")\n",
    "\n",
    "# 프롬프트를 생성합니다.\n",
    "prompt = PromptTemplate.from_template(\n",
    "    \"예/아니오 질문에 대답하세요. {question}는 과일입니까?\"\n",
    ")\n",
    "\n",
    "# 체인을 생성합니다.\n",
    "chain = prompt | model\n",
    "\n",
    "# 결과를 출력합니다.\n",
    "stream_response(chain.stream({\"question\": \"사과\"}))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "477cd3ed",
   "metadata": {},
   "source": [
    "## Safety Settings\n",
    "\n",
    "Gemini 모델에는 기본 안전 설정(Satety Settings) 이 있지만, 이를 재정의할 수 있습니다.\n",
    "\n",
    "만약 모델로부터 많은 \"Safety Warnings\"를 받고 있다면, 모델의 `safety_settings` 속성을 조정해 볼 수 있습니다.\n",
    "\n",
    "Google의 [Safety Setting Types](https://ai.google.dev/api/python/google/generativeai/types/SafetySettingDict) 문서에서는 사용 가능한 카테고리와 임계값에 대한 열거형 정보를 제공합니다.\n",
    "\n",
    "이 문서에는 콘텐츠 필터링 및 안전 설정과 관련된 다양한 카테고리와 해당 임계값이 정의되어 있어, 개발자들이 생성형 AI 모델을 활용할 때 적절한 안전 설정을 선택하고 적용하는 데 도움을 줍니다.\n",
    "\n",
    "이를 통해 개발자들은 모델이 생성하는 콘텐츠의 안전성과 적절성을 보장하고, 사용자에게 유해하거나 부적절한 내용이 노출되는 것을 방지할 수 있습니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2dcad41d",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_google_genai import (\n",
    "    ChatGoogleGenerativeAI,\n",
    "    HarmBlockThreshold,\n",
    "    HarmCategory,\n",
    ")\n",
    "\n",
    "llm = ChatGoogleGenerativeAI(\n",
    "    # 사용할 모델을 \"gemini-pro\"로 지정합니다.\n",
    "    model=\"gemini-1.5-pro-latest\",\n",
    "    safety_settings={\n",
    "        # 위험한 콘텐츠에 대한 차단 임계값을 설정합니다.\n",
    "        # 이 경우 위험한 콘텐츠를 차단하지 않도록 설정되어 있습니다. (그럼에도 기본적인 차단이 있을 수 있습니다.)\n",
    "        HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_NONE,\n",
    "        HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_NONE,\n",
    "        HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_NONE,\n",
    "        HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_NONE,\n",
    "    },\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "515e3df1",
   "metadata": {},
   "source": [
    "## Batch 단위 실행\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3dca2dbf",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_google_genai import ChatGoogleGenerativeAI\n",
    "\n",
    "llm = ChatGoogleGenerativeAI(\n",
    "    # 사용할 모델을 \"gemini-pro\"로 지정합니다.\n",
    "    model=\"gemini-1.5-pro-latest\",\n",
    ")\n",
    "\n",
    "results = llm.batch(\n",
    "    [\n",
    "        \"대한민국의 수도는?\",\n",
    "        \"대한민국의 주요 관광지 5곳을 나열하세요\",\n",
    "    ]\n",
    ")\n",
    "\n",
    "for res in results:\n",
    "    # 각 결과의 내용을 출력합니다.\n",
    "    print(res.content)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c499663d",
   "metadata": {},
   "source": [
    "## Multimodal 모델\n",
    "\n",
    "`langchain-teddynote` 에서 구현한 멀티모달 모델에 `gemini-1.5-pro` 모델을 활용하여 이미지를 텍스트로 변환 가능합니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ddbe79bb",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_teddynote.models import MultiModal\n",
    "from langchain_teddynote.messages import stream_response\n",
    "\n",
    "# 객체 생성\n",
    "gemini = ChatGoogleGenerativeAI(model=\"gemini-1.5-pro-latest\")\n",
    "\n",
    "system_prompt = (\n",
    "    \"당신은 시인입니다. 당신의 임무는 주어진 이미지를 가지고 시를 작성하는 것입니다.\"\n",
    ")\n",
    "\n",
    "user_prompt = \"다음의 이미지에 대한 시를 작성해주세요.\"\n",
    "\n",
    "# 멀티모달 객체 생성\n",
    "multimodal_gemini = MultiModal(\n",
    "    llm, system_prompt=system_prompt, user_prompt=user_prompt\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "37f33aad",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 샘플 이미지 경로(파일의 경로, URL 등)를 지정합니다.\n",
    "IMAGE_URL = \"images/jeju-beach.jpg\"\n",
    "\n",
    "# 이미지 파일로 부터 질의\n",
    "answer = multimodal_gemini.stream(IMAGE_URL)\n",
    "\n",
    "# 스트리밍 방식으로 각 토큰을 출력합니다. (실시간 출력)\n",
    "stream_response(answer)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "py-test",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
